/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.settings.widget;

import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.bluetooth.BluetoothAdapter;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.util.Log;
import android.widget.RemoteViews;

import com.android.settings.R;
import com.android.settings.SecuritySettings;
import com.android.settings.widget.buttons.AirplaneButton;
import com.android.settings.widget.buttons.AutoRotateButton;
import com.android.settings.widget.buttons.BluetoothButton;
import com.android.settings.widget.buttons.BrightnessButton;
import com.android.settings.widget.buttons.FlashlightButton;
import com.android.settings.widget.buttons.GPSButton;
import com.android.settings.widget.buttons.LockScreenButton;
import com.android.settings.widget.buttons.MobileDataButton;
import com.android.settings.widget.buttons.NetworkModeButton;
import com.android.settings.widget.buttons.PowerButton;
import com.android.settings.widget.buttons.ScreenTimeoutButton;
import com.android.settings.widget.buttons.SoundButton;
import com.android.settings.widget.buttons.SyncButton;
import com.android.settings.widget.buttons.WidgetButton;
import com.android.settings.widget.buttons.WifiButton;
import com.android.settings.widget.buttons.WifiApButton;


/**
 * Provides control of power-related settings from a widget.
 */
public class SettingsAppWidgetProvider extends AppWidgetProvider {

	public static final int STATE_DISABLED = 0;
	public static final int STATE_ENABLED = 1;
	public static final int STATE_TURNING_ON = 2;
	public static final int STATE_TURNING_OFF = 3;
	public static final int STATE_UNKNOWN = 4;
	public static final int STATE_INTERMEDIATE = 5;

	public static final int STATE_DISABLED_RED = 10;
	public static final int STATE_ENABLED_RED = 11;
	
	public static final String TAG = "SettingsAppWidgetProvider";

	static final ComponentName THIS_APPWIDGET = new ComponentName(
			"com.android.settings",
			"com.android.settings.widget.SettingsAppWidgetProvider");

	private static final boolean DEBUG=true;

	//New version that allows moving button position. Increase the WIDGET_PRESENT "version"
	public static final int WIDGET_PRESENT = 3; 
	public static final int WIDGET_NOT_CONFIGURED = 1;
	public static final int WIDGET_DELETED = 0;
		
	
	@Override
	public void onEnabled(Context context) {
		logD("Received request to enable first widget");
		PackageManager pm = context.getPackageManager();
		pm.setComponentEnabledSetting(new ComponentName("com.android.settings",
				".widget.SettingsAppWidgetProvider"),
				PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
				PackageManager.DONT_KILL_APP);
	}

	@Override
	public void onDisabled(Context context) {
		logD("Received request to remove last widget");
		PackageManager pm = context.getPackageManager();
		pm.setComponentEnabledSetting(new ComponentName("com.android.settings",
				".widget.SettingsAppWidgetProvider"),
				PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
				PackageManager.DONT_KILL_APP);
	}

	@Override
	public void onDeleted(Context context, int[] appWidgetIds) {
		logD("Received request to remove a widget");
		for (int appWidgetId:appWidgetIds) {
			SharedPreferences widgetPreferences = context.getSharedPreferences(WidgetSettings.WIDGET_PREF_NAME+appWidgetId,
					Context.MODE_PRIVATE);
			Editor editor = widgetPreferences.edit();
			editor.clear();
			editor.putInt(WidgetSettings.SAVED, WIDGET_DELETED);
			editor.commit();
		}
	}

	
	/**
	 * Updates the widget when something changes, or when a button is pushed.
	 * 
	 * @param context
	 */
	public static void updateWidget(Context context) {
		logD(">> updateWidget IN");
		AppWidgetManager manager = AppWidgetManager.getInstance(context);
		int[] widgets = manager.getAppWidgetIds(THIS_APPWIDGET);
		buildUpdate(context, manager, widgets);
		logD("<< updateWidget OUT");
	}


	@Override
	public void onUpdate(Context context, AppWidgetManager appWidgetManager,
			int[] appWidgetIds) {		
		logD(">> onUpdate IN");
		buildUpdate(context, appWidgetManager, appWidgetIds);
		logD("<< onUpdate OUT");
	}

	
	
	/**
	 * update main method. Process all widget. Update state and process all widget instances.
	 */
	static void buildUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
		logD(">> buildUpdate IN");

		SharedPreferences globalPreferences = context.getSharedPreferences(WidgetSettings.WIDGET_PREF_MAIN,Context.MODE_PRIVATE);

		// If never initialized before. Populate the widget with defaults
		if (!globalPreferences.contains(WidgetSettings.SAVED)) {
			Log.d(TAG,"Widget is from a previous version... Let's update");
			//It should be just one when the system is clean... but we never now. So let's process all
			// We shall get them from the system since the update received can be for a single one.
			int[] widgets = appWidgetManager.getAppWidgetIds(THIS_APPWIDGET);
			for (int widget:widgets) {
				Log.d(TAG,"Will set widget "+widget+" to default settings");
				SharedPreferences widgetPreferences = context.getSharedPreferences(WidgetSettings.WIDGET_PREF_NAME+widget,
						Context.MODE_PRIVATE);
				WidgetSettings.initDefaultWidget(widgetPreferences);
			}
			
			if(widgets.length>0) {
				WidgetSettings.initDefaultSettings(globalPreferences);
			} else {
				Log.d(TAG,"No instances yet... Wait for at least one instance to exist before adding global settings");
			}
		}
		//Query for current status of multiple options. Only to be done once
		updateStates(context, globalPreferences, appWidgetIds);
		
		//Now process all widgets instances
		for (int appWidgetId:appWidgetIds) {
			Log.d(TAG,"Call buildUpdate for widget:"+appWidgetId);
			RemoteViews views = updateViews(context, globalPreferences, appWidgetId);
			if (views!=null) {
				appWidgetManager.updateAppWidget(appWidgetId, views);
			}
			Log.d(TAG,"buildUpdate done for widget:"+appWidgetId);
		}		
		logD("<< buildUpdate OUT");

	}

	/**
	 * Method that will trigger the update for all options
	 */
	private static void updateStates(Context context, SharedPreferences globalPreferences,  int[] appWidgetIds) {
		WifiButton.getInstance().updateState(context, globalPreferences, appWidgetIds);
		WifiApButton.getInstance().updateState(context, globalPreferences, appWidgetIds);
		BluetoothButton.getInstance().updateState(context, globalPreferences, appWidgetIds);
		GPSButton.getInstance().updateState(context, globalPreferences, appWidgetIds);
		MobileDataButton.getInstance().updateState(context, globalPreferences, appWidgetIds);;
		NetworkModeButton.getInstance().updateState(context, globalPreferences, appWidgetIds);
		SyncButton.getInstance().updateState(context, globalPreferences, appWidgetIds);
		SoundButton.getInstance().updateState(context, globalPreferences, appWidgetIds);
		AutoRotateButton.getInstance().updateState(context, globalPreferences, appWidgetIds);
		ScreenTimeoutButton.getInstance().updateState(context, globalPreferences, appWidgetIds);
		AirplaneButton.getInstance().updateState(context, globalPreferences, appWidgetIds);
		LockScreenButton.getInstance().updateState(context, globalPreferences, appWidgetIds);
		FlashlightButton.getInstance().updateState(context, globalPreferences, appWidgetIds);
		BrightnessButton.getInstance().updateState(context, globalPreferences, appWidgetIds);
	}

	/**
	 * Update of each widget instance. will check it's configuration
	 */
	private static RemoteViews updateViews(Context context, SharedPreferences globalPreferences, int appWidgetId) {
		logD(">> updateViews IN - Widget:"+appWidgetId);
		SharedPreferences widgetPreferences = context.getSharedPreferences(WidgetSettings.WIDGET_PREF_NAME+appWidgetId,
				Context.MODE_PRIVATE);

		// If not configured do not refresh. Needed due to: 
		// 1: Ghost instances of the launcher
		// 2: Older version no longer compatible. So widget_present was increased
		if(widgetPreferences.getInt(WidgetSettings.SAVED,WIDGET_NOT_CONFIGURED)==WIDGET_PRESENT) {
			
			//Set the selected background. On a widget it can only be done by a diferent layout.
			
			int widgetLayout = R.layout.widget;
			int backgroundLayout= widgetPreferences.getInt(WidgetSettings.BACKGROUND_IMAGE, 0);
			boolean verticalLayout = widgetPreferences.getBoolean(WidgetSettings.USE_VERTICAL, false);
			if (!verticalLayout && backgroundLayout==WidgetSettings.TRANSPARENT_BACKGROUND) {
				widgetLayout = R.layout.widget_transparent;
			}else if (verticalLayout && backgroundLayout==WidgetSettings.TRANSPARENT_BACKGROUND) {
				widgetLayout = R.layout.widget_vertical_transparent;
/*			}else if (verticalLayout && backgroundLayout==WidgetSettings.WHITE_BACKGROUND) {
				widgetLayout = R.layout.widget_white_vertical;
			}else if (!verticalLayout && backgroundLayout==WidgetSettings.WHITE_BACKGROUND) {
				widgetLayout = R.layout.widget_white;*/
			}else if (verticalLayout) {
				widgetLayout = R.layout.widget_vertical;
			}		
			
			// create the new remote views
			RemoteViews views = new RemoteViews(context.getPackageName(),
					widgetLayout);
			
				//Now call each button to update it's state on this instance. 
				WifiButton.getInstance().updateView(context, views, globalPreferences, widgetPreferences, appWidgetId);
				WifiApButton.getInstance().updateView(context, views, globalPreferences, widgetPreferences, appWidgetId);
				BluetoothButton.getInstance().updateView(context, views, globalPreferences, widgetPreferences, appWidgetId);
				GPSButton.getInstance().updateView(context, views, globalPreferences, widgetPreferences, appWidgetId);
				MobileDataButton.getInstance().updateView(context, views, globalPreferences, widgetPreferences, appWidgetId);
				NetworkModeButton.getInstance().updateView(context, views, globalPreferences, widgetPreferences, appWidgetId);
				SyncButton.getInstance().updateView(context, views, globalPreferences, widgetPreferences, appWidgetId);
				SoundButton.getInstance().updateView(context, views, globalPreferences, widgetPreferences, appWidgetId);
				AutoRotateButton.getInstance().updateView(context, views, globalPreferences, widgetPreferences, appWidgetId);
				ScreenTimeoutButton.getInstance().updateView(context, views, globalPreferences, widgetPreferences, appWidgetId);
				BrightnessButton.getInstance().updateView(context, views, globalPreferences, widgetPreferences, appWidgetId);
				FlashlightButton.getInstance().updateView(context, views, globalPreferences, widgetPreferences, appWidgetId);
				LockScreenButton.getInstance().updateView(context, views, globalPreferences, widgetPreferences, appWidgetId);
				AirplaneButton.getInstance().updateView(context, views, globalPreferences, widgetPreferences, appWidgetId);

			return views;
		} else {
			// Return the layout with widget configuration message.
			RemoteViews views = new RemoteViews(context.getPackageName(),
					R.layout.widget_configure);
			
			logD(">> updateViews IN - Widget:"+appWidgetId+" no longer present or not configured");
			return views;
		}
	}

	
	/**
	 * Receives and processes a button pressed intent or state change.
	 * 
	 * @param context
	 * @param intent
	 *            Indicates the pressed button.
	 */
	@Override
	public void onReceive(Context context, Intent intent) {
		logD(">> onReceive IN");		
		super.onReceive(context, intent);
		if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) {
			logD("Received Wifi state change");
			WifiButton.getInstance().onReceive(context, intent);
		} else if (WifiManager.WIFI_AP_STATE_CHANGED_ACTION.equals(intent.getAction())) {
			logD("Received Wifi AP state change");
			WifiApButton.getInstance().onReceive(context, intent);
		} else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
			logD("Received Bluetooth state change");
			BluetoothButton.getInstance().onReceive(context, intent);
		} else if (NetworkModeButton.NETWORK_MODE_CHANGED.equals(intent.getAction())) {
			logD("Received Network mode state change");
			NetworkModeButton.getInstance().onReceive(context, intent);
		} else if (Intent.ACTION_POWER_CONNECTED.equals(intent.getAction()) ||
				Intent.ACTION_POWER_DISCONNECTED.equals(intent.getAction())) {
			logD("Received power mode state change");
			PowerButton.getInstance().onReceive(context, intent);
		} else if (intent.hasCategory(Intent.CATEGORY_ALTERNATIVE)) {
			Uri data = intent.getData();
			int buttonId = Integer.parseInt(data.getSchemeSpecificPart());
			if (buttonId == WidgetButton.BUTTON_WIFI) {
				logD("Received wifi button change request");
				WifiButton.getInstance().toggleState(context);
			} else if (buttonId == WidgetButton.BUTTON_WIFI_AP) {
				logD("Received wifi ap button change request");
				WifiApButton.getInstance().toggleState(context);
			} else if (buttonId == WidgetButton.BUTTON_BLUETOOTH) {
				logD("Received bluetooth button change request");
				BluetoothButton.getInstance().toggleState(context);				
			} else if (buttonId == WidgetButton.BUTTON_GPS) {
				logD("Received GPS button change request");
				GPSButton.getInstance().toggleState(context);				
			} else if (buttonId == WidgetButton.BUTTON_DATA) {
				logD("Received mobile data button change request");
				MobileDataButton.getInstance().toggleState(context);				
			} else if (buttonId == WidgetButton.BUTTON_2G3G) {
				logD("Received network mode button change request");
				NetworkModeButton.getInstance().toggleState(context);				
			} else if (buttonId == WidgetButton.BUTTON_SYNC) {
				logD("Received sync button change request");
				SyncButton.getInstance().toggleState(context);				
			} else if (buttonId == WidgetButton.BUTTON_SOUND) {
				logD("Received sound button change request");
				SoundButton.getInstance().toggleState(context);				
			} else if (buttonId == WidgetButton.BUTTON_SCREEN_TIMEOUT) {
				logD("Received screen timeout change request");
				ScreenTimeoutButton.getInstance().toggleState(context);				
			} else if (buttonId == WidgetButton.BUTTON_AUTO_ROTATE) {
				logD("Received auto rotate change request");
				AutoRotateButton.getInstance().toggleState(context);
			} else if (buttonId == WidgetButton.BUTTON_BRIGHTNESS) {
				logD("Received brightness change request");
				BrightnessButton.getInstance().toggleState(context);				
			} else if (buttonId == WidgetButton.BUTTON_FLASHLIGHT) {
				logD("Received flahslight change request");
				FlashlightButton.getInstance().toggleState(context);				
			} else if (buttonId == WidgetButton.BUTTON_LOCK_SCREEN) {
				logD("Received Lock Screen change request");
				LockScreenButton.getInstance().toggleState(context);
			} else if (buttonId == WidgetButton.BUTTON_AIRPLANE) {
				logD("Received airplane change request");
				AirplaneButton.getInstance().toggleState(context);				
			}
		} else if (MobileDataButton.MOBILE_DATA_CHANGED.equals(intent.getAction())||  
					Intent.ACTION_USER_PRESENT.equals(intent.getAction()) ||
					SecuritySettings.GPS_STATUS_CHANGED.equals(intent.getAction())) {
		} else {
			logD("Ignoring Action: "+intent.getAction());
			// Don't fall-through to updating the widget. The Intent
			// was something unrelated or that our super class took
			// care of.
			logD("<< onReceive OUT");		
			return;
		}
		updateWidget(context);
		// State changes fall through
		logD("<< onReceive OUT");		
		
	}
	
	public static void logD(String message) {
		if (DEBUG) Log.d(TAG,message);
		
	}
}
